#include <iostream>
#include <unistd.h>
#include <cassert>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <sys/wait.h>
#include "task.hpp"
#define NUM 5
// 对于每个管道，先描述再组织
struct channel
{
    pid_t _childId; // 管道读端进程pid，即对应任务进程的pid
    int _ctrlfd;    // 管道写端文件描述符，即对应控制进程的pid
    std::string _name;
    static int num;

    channel(pid_t id, int fd)
        : _childId(id), _ctrlfd(fd)
    {
        _name = "channel_" + std::to_string(num++);
    }
};
void Work()
{
    while(true)
    {
        int code = 0;
        int n = read(0,&code,sizeof(code));
        if(n == sizeof(code))
        {
            if(!CheckCode(code))
                continue;
            tasks[code].RunTask();
        }
        else if(n == 0)
        {
            break;
        }
        else
        {
            ; //啥也不做
        }
    }
}
int channel::num = 0;
void CreateChannels(std::vector<channel> *c)
{
    std::vector<int> old; //记录父进程之前创建的写端
    for (int i = 0; i < NUM; i++)
    {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n; // 防止编译器警告

        pid_t id = fork(); // 创建进程，给子进程返回值为0，给父进程返回子进程的pid
        assert(id >= 0);

        if (id == 0) // 子进程
        {
            if(!old.empty()) //关掉应创建进程从父进程那得到的无效的写端
            {
                for(auto fd : old)
                {
                    close(fd);
                }
            }
            // 关掉写端
            close(pipefd[1]);
            dup2(pipefd[0], 0); // 重定向到标准输入，之后直接从fd=0处读
            Work();
            exit(0);
        }
        // 父进程关掉读端
        close(pipefd[0]);
        c->push_back(channel(id,pipefd[1]));
        old.push_back(pipefd[1]);
    }
}
void PrintDebug(const std::vector<channel>& c)
{
    for (const auto &channel : c)
    {
        std::cout << channel._name << ", " << channel._ctrlfd << ", " << channel._childId << std::endl;
    }
}

void SendCommand(const std::vector<channel> &c,bool flag = true,int num = -1)
{
    int pos = 0;
    while(true)
    {
        //1、选择任务
        int code = SelectTask();

        //2、选择管道
        const auto &channel = c[pos++];
        pos = pos % c.size();

        //Debug
        std::cout << "Task : " << GetTaskName(code) << " in "<< channel._name << " worker is : " << channel._childId << std::endl;
        //3、发送任务
        write(channel._ctrlfd,&code,sizeof(code));
        if(!flag)
        {
            num--;
            if(num <= 0)
            {
                break;
            }
        }

        sleep(1);
    }
    std::cout << "SendCommand done..." << std::endl;
}
void ReleaseChannels(std::vector<channel>& c)
{
    for(const auto channel : c)
    {
        close(channel._ctrlfd);
        waitpid(channel._childId,nullptr,0);
    }
}
int main()
{
    srand((unsigned int)time(nullptr));
    std::vector<channel> channels;
    // 1、创建num个进程
    CreateChannels(&channels);
    PrintDebug(channels);
    // 2、开始发送任务
    const bool g_always_loop = true;
    SendCommand(channels,g_always_loop,10);  
    // 3、回收资源
    ReleaseChannels(channels);

    return 0;
    
}
